package edu.gatech.mobile.scene.image.util;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;
import org.opencv.features2d.DescriptorMatcher;

import android.app.Activity;
import android.database.Cursor;
import edu.gatech.mobile.scene.AppConstants;
import edu.gatech.mobile.scene.AppConstants.RELATIVE_TO_HORIZON;
import edu.gatech.mobile.scene.ApplicationContext;
import edu.gatech.mobile.scene.model.ImageInfo;
import edu.gatech.mobile.scene.model.MaskInfo;
import edu.gatech.mobile.scene.provider.impl.ImageInfoDBImpl;
import edu.gatech.mobile.scene.provider.impl.MaskInfoDBImpl;

public class MatUtil {

	public static void fillMatcherMat(Mat mat, MaskInfo mask, int row) {
		int colIndex = 0;
		for (Mat colorMat : mask.getHistograms().getColorHistogram()) {
			for (int matIndex = 0; matIndex < AppConstants.COLOR_HISTOMGRAM_BIN_SIZE; matIndex++) {
				float[] data = new float[1];
				colorMat.get(matIndex, 0, data);
				mat.put(row, colIndex, data);
				colIndex++;
			}
		}
	}

	public static boolean initializeApplicationContext(Activity applicationContext) {

		ApplicationContext context = (ApplicationContext) applicationContext
				.getApplicationContext();
		if (ApplicationContext.contextLoaded == false) {
			int aboveMaskIndex = 0;
			int onMaskIndex = 0;
			int belowMaskIndex = 0;

			ImageInfoDBImpl imageDB = new ImageInfoDBImpl(applicationContext);
			MaskInfoDBImpl maskDB = new MaskInfoDBImpl(applicationContext);

			List<Long> aboveMaskImages = new ArrayList<Long>();
			List<Long> onMaskImages = new ArrayList<Long>();
			List<Long> belowMaskImages = new ArrayList<Long>();

			List<Integer> aboveMaskColors = new ArrayList<Integer>();
			List<Integer> onMaskColors = new ArrayList<Integer>();
			List<Integer> belowMaskColors = new ArrayList<Integer>();

			DescriptorMatcher aboveMatcher = DescriptorMatcher
					.create(DescriptorMatcher.FLANNBASED);
			DescriptorMatcher onMatcher = DescriptorMatcher
					.create(DescriptorMatcher.FLANNBASED);
			DescriptorMatcher belowMatcher = DescriptorMatcher
					.create(DescriptorMatcher.FLANNBASED);

			int maskCount = 0;

			int aboveCount = maskDB
					.getMaskCountWithHorizon(RELATIVE_TO_HORIZON.ABOVE);
			int onCount = maskDB
					.getMaskCountWithHorizon(RELATIVE_TO_HORIZON.ON);
			int belowCount = maskDB
					.getMaskCountWithHorizon(RELATIVE_TO_HORIZON.BELOW);

			Mat aboveData = new Mat(aboveCount,
					AppConstants.COLOR_HISTOMGRAM_BIN_SIZE * 3, CvType.CV_32F);
			Mat onData = new Mat(onCount,
					AppConstants.COLOR_HISTOMGRAM_BIN_SIZE * 3, CvType.CV_32F);
			Mat belowData = new Mat(belowCount,
					AppConstants.COLOR_HISTOMGRAM_BIN_SIZE * 3, CvType.CV_32F);
			Scalar zeroScalar = new Scalar(0);
			aboveData.setTo(zeroScalar);
			onData.setTo(zeroScalar);
			belowData.setTo(zeroScalar);

			Cursor imageCursor = imageDB.getUseImagesCursor(true);
			while (imageCursor != null && imageCursor.getCount() > 0
					&& !imageCursor.isLast()) {
				ImageInfo trainingImage = ImageInfoDBImpl
						.fillFromCursor(imageCursor);

				System.out.println("MaskCount: " + maskCount + "  "
						+ trainingImage.getImagePath());
				for (MaskInfo mask : trainingImage.getMasks()) {
					RELATIVE_TO_HORIZON position = mask.getHorizonPosition();
					mask.getHistograms().normalizeColorHistogram();
					if (position.equals(RELATIVE_TO_HORIZON.BELOW)) {
						belowMaskImages.add(mask.getId());
						belowMaskColors.add(mask.getLabelInfo().getColor());
						MatUtil.fillMatcherMat(belowData, mask, belowMaskIndex);
						belowMaskIndex++;
					}

					if (position.equals(RELATIVE_TO_HORIZON.ON)) {
						onMaskImages.add(mask.getId());
						onMaskColors.add(mask.getLabelInfo().getColor());
						MatUtil.fillMatcherMat(onData, mask, onMaskIndex);
						onMaskIndex++;

					}
					if (position.equals(RELATIVE_TO_HORIZON.ABOVE)) {
						aboveMaskImages.add(mask.getId());
						aboveMaskColors.add(mask.getLabelInfo().getColor());
						MatUtil.fillMatcherMat(aboveData, mask, aboveMaskIndex);
						aboveMaskIndex++;
					}
				}
				maskCount += trainingImage.getMasks().size();
			}

			safelyCloseCursor(imageCursor);

			for (int index = belowMaskImages.size(); index < belowCount; index++) {
				belowMaskImages.add(0L);
				belowMaskColors.add(0);
			}
			for (int index = onMaskImages.size(); index < onCount; index++) {
				onMaskImages.add(0L);
				onMaskColors.add(0);
			}
			for (int index = aboveMaskImages.size(); index < aboveCount; index++) {
				aboveMaskImages.add(0L);
				aboveMaskColors.add(0);
			}

			List<Mat> aboveList = new ArrayList<Mat>();
			aboveList.add(aboveData);
			aboveMatcher.add(aboveList);

			List<Mat> onList = new ArrayList<Mat>();
			onList.add(onData);
			onMatcher.add(onList);

			List<Mat> belowList = new ArrayList<Mat>();
			belowList.add(belowData);
			belowMatcher.add(belowList);

			context.setAboveData(aboveData);
			context.setAboveMaskColors(aboveMaskColors);
			context.setAboveMaskImages(aboveMaskImages); 
			context.setAboveMatcher(aboveMatcher);

			context.setBelowData(belowData);
			context.setBelowMaskColors(belowMaskColors);
			context.setBelowMaskImages(belowMaskImages);
			context.setBelowMatcher(belowMatcher);

			context.setOnData(onData);
			context.setOnMaskColors(onMaskColors);
			context.setOnMaskImages(onMaskImages);
			context.setOnMatcher(onMatcher);
			
			ApplicationContext.contextLoaded = true;
		}
		return true;
	}

	private static void safelyCloseCursor(Cursor cur) {
		if (cur != null && cur.isClosed() == false)
			cur.close();
	}

}
